/*
 *  linux/kernel/asm.s
 *
 *  (C) 1991  Linus Torvalds
 */

/* asm.s程序中包括大部分的硬件故障或出错处理的底层次代码。页一场是由内存管理程序mm处理的，所以不在这里。此程序还处理由于 TS-位而造成的fpu异常，因为fpu必须正确地进行保存恢复处理
 * asm.s contains the low-level code for most hardware faults.
 * page_exception is handled by the mm, so that isn't here. This
 * file also handles (hopefully) fpu-exceptions due to TS-bit, as
 * the fpu must be properly saved/resored. This hasn't been tested.
 */
# 本代码文件主要设计对 Intel 保留的中断int0-int16的处理（int17-int31留作今后使用） 以下是一些全局函数名的声明，其原型在 traps.c 中说明
.globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op
.globl _double_fault,_coprocessor_segment_overrun
.globl _invalid_TSS,_segment_not_present,_stack_segment
.globl _general_protection,_coprocessor_error,_irq13,_reserved

_divide_error:              # 下面是 除0 出错处理代码 int 0
	pushl $_do_divide_error # 首先是要将调用的函数地址入栈。这段程序的出错号是0。这里是无出错号处理的入口处，见下面第55行等。_do_divide_error->eax，eax 被交换入栈
no_error_code:                          # 几乎是通用的异常处理程序
	xchgl %eax,(%esp)
	pushl %ebx
	pushl %ecx
	pushl %edx
	pushl %edi
	pushl %esi
	pushl %ebp
	push %ds                            # 16位的段寄存器也要占用 4 个字节
	push %es
	push %fs
	pushl $0		# "error code"      # error_code 将出错码入栈
	lea 44(%esp),%edx                   # 取原调用返回地址处堆栈指针位置，并压入堆栈
	pushl %edx
	movl $0x10,%edx                     # 内核代码 数据段选择符
	mov %dx,%ds
	mov %dx,%es
	mov %dx,%fs
	call *%eax                          # 调用之前 push 进来的 C 函数
	addl $8,%esp                        # 让堆栈指针重新指向寄存器 fs 入栈处
	pop %fs
	pop %es
	pop %ds
	popl %ebp
	popl %esi
	popl %edi
	popl %edx
	popl %ecx
	popl %ebx
	popl %eax                           # 弹出原来的内容
	iret

_debug:                                 # int 1 debug 调试中断入口点。 处理过程同上
	pushl $_do_int3		# _do_debug     # _do_debug 将C函数入栈
	jmp no_error_code

_nmi:                                   # int 2 非屏蔽中断调用入口点
	pushl $_do_nmi
	jmp no_error_code

_int3:                                  # int 3 断点指令引起中断的入口点，处理过程同 _debug
	pushl $_do_int3
	jmp no_error_code

_overflow:                              # int 4 溢出检查出错中断入口点
	pushl $_do_overflow
	jmp no_error_code

_bounds:                                # int 5 边界检查出错中断入口点
	pushl $_do_bounds
	jmp no_error_code

_invalid_op:                            # int 6 无效操作指令出错中断入口点
	pushl $_do_invalid_op
	jmp no_error_code

_coprocessor_segment_overrun:           # int 9 协处理器段超出出错中断入口点
	pushl $_do_coprocessor_segment_overrun
	jmp no_error_code

_reserved:                              # int 15 保留
	pushl $_do_reserved
	jmp no_error_code

_irq13:                                 # 这个用于当协处理器执行完一个操作时就会发出 IRQ13 中断信号,以通知CPU操作完成。
	pushl %eax                          # int 45 数学协处理器发出的中断
	xorb %al,%al                        # 80387 在执行计算时，CPU会等待其操作的完成
	outb %al,$0xF0                      # 通过写0xF0端口，本中断消除CPU的BUSY延续信号，并重新激活387的处理器扩展请求引脚PEREQ 该操作主要是为了确保在继续执行287的任何指令之前，响应本中断
	movb $0x20,%al
	outb %al,$0x20                      # 向 8259 主中断控制芯片发送 EOI（中断结束） 信号
	jmp 1f
1:	jmp 1f
1:	outb %al,$0xA0                      # 再向8259从中断控制芯片发送 EOI（中断结束）信号
	popl %eax
	jmp _coprocessor_error              # _coprocessor_error 原来在本文件中，现在已经放到 kernel/system_call.s

_double_fault:                          # 中断在调用时会在中断返回地址之后将出错号压入堆栈，因此返回时也需要将出错号弹出。 int 8 双出错故障
	pushl $_do_double_fault             # C函数地址 入栈
error_code:
	xchgl %eax,4(%esp)		# error code <-> %eax   eax 原来的值被保存在堆栈上
	xchgl %ebx,(%esp)		# &function <-> %ebx    ebx 原来的值被保存在堆栈上
	pushl %ecx
	pushl %edx
	pushl %edi
	pushl %esi
	pushl %ebp
	push %ds
	push %es
	push %fs
	pushl %eax			# error code    # 出错号入栈
	lea 44(%esp),%eax		# offset    # 程序返回地址处堆栈指针位置值入栈
	pushl %eax
	movl $0x10,%eax                     # 置内核数据段选择符
	mov %ax,%ds
	mov %ax,%es
	mov %ax,%fs
	call *%ebx                          # 调用相应的C函数，其参数已入栈
	addl $8,%esp                        # 堆栈指针重新指向栈中放置fs内容的位置
	pop %fs
	pop %es
	pop %ds
	popl %ebp
	popl %esi
	popl %edi
	popl %edx
	popl %ecx
	popl %ebx
	popl %eax
	iret

_invalid_TSS:                           # int 10 无效任务状态段
	pushl $_do_invalid_TSS
	jmp error_code

_segment_not_present:                   # int 11 段不存在
	pushl $_do_segment_not_present
	jmp error_code

_stack_segment:                         # int 12 堆栈段错误
	pushl $_do_stack_segment
	jmp error_code

_general_protection:                    # 一般保护性出错
	pushl $_do_general_protection
	jmp error_code

# int 7 设备不存在
# int 14 页错误
# int 16 协处理器错误
# int 0x20 _timer_interrupt
# int 0x80 _system_call

